(Thanks to Raphaƫl Quinet who wrote most of this section)
The sprites are used in Quake to represent objects that could not be rendered properly using polygons (because of a shape with too many small details) or that were not worth the trouble of using polygons (they render faster than Alias models or BSP based models).
The sprites are essentially designed for stuff like explosions, fire, magical effect, or the like. They can also be used for simple objects that have a vertical axis of rotation, like torches or barrels.
The format of the sprites is rather simple. Basically, this is a list of 2D pictures (flat bitmaps) organized in lumps.
Some frames are grouped in animation sequences, that start with the first picture in the animation and automatically proceed to the next, at the time values indicated in the beginning of the sequence.
The sprite files (.SPR) begin with a header, which is immediately followed by the list of frames. There are no pointers to the individual pictures, which means that the engine probably reads and parses the whole file once and for all, because the only way to access a given picture is to read all previous frames and know their width and height.
Here is the format of the .SPR file header:
typedef struct { char name[4]; // "IDSP" long ver1; // Version = 1 long type; // See below float radius; // Bounding Radius long maxwidth; // Width of the largest frame long maxheight; // Height of the largest frame long nframes; // Number of frames float beamlength; // long synchtype; // 0=synchron 1=random } spr_t;
The size of this header is 0x24 bytes.
Type of sprites:
There are two types of frames. Most of them contain a single picture, but some of them (in s_torch.spr and shots.spr) contain multiple pictures associated with floating point values.
The first kind of frames are marked with a leading (long) zero, followed by the picture data:
long group; // Always 0 for single-picture frames picture pic; // Picture data, see below
The second kind of frames are marked with a leading 0x1 or 0x10000000, followed by the number of pictures, a list of floating point values, and a list of pictures:
long group; // not zero (0x1 or 0x10000000) long npics; // Number of pictures float times[npics]; // 0.0, 0.2, 0.3, ... picture pic[npics]; // Pictures
The times are offsets that describe when the corresponding picture shall be displayed, relative to an animation frame that repeats regularly. 0.0 means start of the animation frame, and 1.0 is the end. So if you have npics pictures, and want a regular sequence of pictures, you will start from 0.0 and regularly increase the dates by 1/npics.
By the way... the above is just a wild guess. But what the heck can it be, if it's not time stamps?
The format of each individual picture is given below. It contains the X and Y offsets, the width and height of the picture, followed by the list of pixels. The reference to the Quake palette is implicit and the value 0xFF denotes a transparent pixel.
typedef struct { long ofsx; // horizontal offset, in 3D space long ofsy; // vertical offset, in 3D space long width; // width of the picture long height; // height of the picture char Pixels[width*height]; // array of pixels (flat bitmap) } picture;